package com.thiswhyme.fsplus.sentinel.feign.defaultfallback;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.netflix.client.ClientException;
import com.thiswhyme.common.response.ResponseVo;
import feign.FeignException;
import feign.RetryableException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ConnectTimeoutException;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;

import java.lang.reflect.Method;
import java.net.SocketTimeoutException;
import java.util.Objects;

/**
 * @description: 默认fallback
 * @author: thiswhyme
 * @date: 2020/10/30
 */
@Slf4j
public class DefaultFeignFallback<T> implements MethodInterceptor {

    public DefaultFeignFallback(Class<T> targetType, String targetName, Throwable cause) {
        this.targetType = targetType;
        this.targetName = targetName;
        this.cause = cause;
    }

    private final Class<T> targetType;
    private final String targetName;
    private final Throwable cause;

    @Nullable
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String errorMessage = cause.getMessage();
        log.error("默认Fallback:[{}.{}] serviceId:[{}] 异常：", targetType.getName(), method.getName(), targetName, cause);

        if(cause instanceof BlockException) {
            if(cause instanceof DegradeException) {
                return ResponseVo.failure("4271", "服务熔断") ;
            } else if(cause instanceof FlowException) {
                return ResponseVo.failure("4272", "服务限流") ;
            } else if(cause instanceof ParamFlowException) {
                return ResponseVo.failure("4273", "热点参数限流") ;
            }
            return ResponseVo.failure("427", "其他限流") ;
        } else if(cause instanceof RetryableException) {
            if(null != cause.getCause()) {
                if(cause.getCause() instanceof SocketTimeoutException) {
                    return ResponseVo.failure("4281", "调用外部服务超时-读取超时") ;
                } else if(cause.getCause() instanceof ConnectTimeoutException) {
                    return ResponseVo.failure("4282", "调用外部服务超时-连接超时") ;
                } else if(null != cause.getCause().getCause() && cause.getCause().getCause() instanceof BlockException) {
                    if(cause.getCause().getCause() instanceof DegradeException) {
                        return ResponseVo.failure("4271", "ip-服务熔断") ;
                    } else if(cause.getCause().getCause() instanceof FlowException) {
                        return ResponseVo.failure("4272", "ip-服务限流") ;
                    } else if(cause.getCause().getCause() instanceof ParamFlowException) {
                        return ResponseVo.failure("4273", "ip-热点参数限流") ;
                    }
                    return ResponseVo.failure("427", "ip-其他限流") ;
                }
            }
            return ResponseVo.failure("428", "调用外部服务超时") ;
        } else if(cause instanceof RuntimeException && null != cause.getCause() && cause.getCause() instanceof ClientException) {
            return ResponseVo.failure("429", "外部服务掉线") ;
        } else if(cause instanceof FeignException) {
            return ResponseVo.failure("430", "其他feign调用异常") ;
        } else {
            return ResponseVo.failure("431", "系统繁忙，请稍后重试") ;
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        DefaultFeignFallback<?> that = (DefaultFeignFallback<?>) o;
        return targetType.equals(that.targetType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(targetType);
    }
}

